#define _GNU_SOURCE
#include "daemon_sub_process.h"
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <sys/reboot.h>
#include <signal.h>
#include "log/log.h"

/**
 * @brief 初始化子进程
 *
 * @param cmd_param 子进程命令参数
 * @return Suprocess_t* 子进程结构体指针
 */
Suprocess_t *daemon_sub_process_init(char *cmd_param)
{
    Suprocess_t *sub_process = (Suprocess_t *)malloc(sizeof(Suprocess_t));
    sub_process->cmd_param = cmd_param;
    // 子进程还没产生
    sub_process->pid = 0;
    sub_process->fail_count = 0;

    return sub_process;
}

/**
 * @brief 检查并启动子进程
 *
 * @param sub_process 子进程结构体指针
 * @return int 0成功，-1失败
 */
int daemon_sub_process_checkStart(Suprocess_t *sub_process)
{
    // 检查子进程是否已经启动
    int status = 0;
    // WNOHANG:不会一直等待，只会检查是否有子进程已经退出，返回值为0表示正常运行，返回值为pid表示已经退出，返回值为-1表示没有子进程
    // status:如果子进程是正常退出，则status为0，如果子进程是异常退出，则status为不为0
    if ((sub_process->pid > 0) && (waitpid(sub_process->pid, &status, WNOHANG) == 0))
    {
        // 子进程已经启动
        log_debug("子进程%d正在运行中...", sub_process->cmd_param);
        return 0;
    }
    // 如果子进程是异常结束，统计失败次数, 如果超过了最大失败次数，则重启系统
    if (status != 0)
    {
        sub_process->fail_count++;
        if (sub_process->fail_count > MAX_FAIL_COUNT)
        {
            reboot(RB_AUTOBOOT);
        }
    }

    // 则创建子进程，并在子进程中运行对应的程序
    sub_process->pid = fork();
    if (sub_process->pid == 0)
    {
        // 运行指定程序模块
        /*
        gateway_test app  子进程
        gateway_test ota  子进程
        */
        char *argv[] = {EXE_PATH, sub_process->cmd_param, NULL};
        execve(EXE_PATH, argv, NULL);
        log_error("----, %s", sub_process->cmd_param);
        // 找不到对应的程序模块，结束当前进程
        _exit(EXIT_FAILURE);
    }

    return 0;
}

/**
 * @brief 结束子进程
 *
 * @param sub_process 子进程结构体指针
 * @return int 0成功，-1失败
 */
int daemon_sub_process_stop(Suprocess_t *sub_process)
{
    // kill子进程, 并发送SIGTERM信号通知子进程
    kill(sub_process->pid, SIGTERM);
    // 等待子进程结束
    waitpid(sub_process->pid, NULL, 0);
    // 释放内存
    free(sub_process);
    return 0;
}